AWS Step Functionsで、音声ファイルがS3バケットに保存される度にAmazon Transcribeで文字起こしし、内容をメール送信してみた

AWS Step Functionsで、音声ファイルがS3バケットに保存される度にAmazon Transcribeで文字起こしし、内容をメール送信してみた

Clock Icon2024.07.18

はじめに

AWS Step Functionsを利用し、音声ファイルがS3バケットに保存されるたびにAmazon Transcribeで文字起こしを行い、文字起こし内容をメール送信する方法を紹介します。

今回構築する構成は以下の通りです。

cm-hirai-screenshot 2024-07-16 14.39.00

処理の流れは以下の通りです。

  1. 音声ファイル(WAV)をS3バケットにアップロードする
  2. アップロードをトリガーにEventBridgeからStep Functionsステートマシンを起動する
  3. 音声ファイルからAmazon Transcribeで文字起こしし、文字起こした内容をAmazon SNSでメール送信する

この構成を構築するきっかけは、以前執筆した「Amazon Connectでエージェントの介在がない場合でも電話中の発話を録音する」記事の構成に、録音ファイルに対して文字起こしとメール通知機能を追加する必要が生じたためです。

https://dev.classmethod.jp/articles/amazon-connect-kinesis-data-streams/

執筆した記事の構成図は以下の通りです。

cm-hirai-screenshot 2024-07-16 14.38.51

今回新たに必要となった構成は以下の図の通りです。

cm-hirai-screenshot 2024-07-16 15.08.46

今回は、S3バケットへの音声ファイルの保存をトリガーとし、文字起こしからメール通知までの一連の処理をStep Functions ステートマシンでコントロールします。

以下の順序でAWSリソースを作成していきます。

  • SNSトピック作成
  • S3バケット作成
  • IAMポリシー作成
  • ステートマシン作成
  • EventBridgeルール作成

SNSトピック作成

SNSのメール通知の本文には通知を停止するリンクが記載されています。このリンクをクリックすると登録解除(Unsubscribe)されてしまうため、今回はこの登録解除を無効にする設定を行います。詳細は以下の記事をご参照ください。

https://dev.classmethod.jp/articles/amazon-sns-disable-unsubscribe-link/

https://dev.classmethod.jp/articles/prevent-unsubscribe-all-sns-topic/

SNSトピックは、タイプをスタンダードにし、名前を記載します。ほかはデフォルトとしてます。

cm-hirai-screenshot 2024-07-16 14.48.40

サブスクリプションをプロトコルをEメールにして作成します。

cm-hirai-screenshot 2024-07-16 14.49.13

登録したメールアドレスに対して、件名[AWS Notification - Subscription Confirmation]というメールが届きます。

以下の赤枠の[Confirm subscription]というリンクを右クリックして、リンクのアドレスをコピーします。

cm-hirai-screenshot 2024-07-16 14.58.03

コピーしたリンクの内容は以下の通りです。この中からTokenの値(aaaaaaaaa)をコピーしてください。

https://sns.ap-northeast-1.amazonaws.com/confirmation.html?TopicArn=arn:aws:sns:ap-northeast-1:xxxxxxxxxxxx:cm-hirai&Token=aaaaaaaaa&[email protected]

AWSマネジメントコンソールからCloudShellを開き、以下のコマンドを実行します。
コマンド中の[SNSトピックARN]と[Token]の部分を、それぞれ実際の値に置き換えてください。

$ aws sns confirm-subscription \
 --topic-arn arn:aws:sns:ap-northeast-1:xxxxxxxxxxxx:cm-hirai \
 --token aaaaaaaaa \
 --authenticate-on-unsubscribe true \
 --region ap-northeast-1

{
    "SubscriptionArn": "arn:aws:sns:ap-northeast-1:xxxxxxxxxxxx:cm-hirai:xxxxxx"
}

$ aws sns get-subscription-attributes\
   --subscription-arn arn:aws:sns:ap-northeast-1:xxxxxxxxxxxx:cm-hirai:xxxxxx

{
    "Attributes": {
        "SubscriptionPrincipal": "arn:aws:iam::xxxxxxxxxxxx:role/xxxx",
        "Owner": "xxxxxxxxxxxx",
        "RawMessageDelivery": "false",
        "TopicArn": "arn:aws:sns:ap-northeast-1:xxxxxxxxxxxx:cm-hirai",
        "Endpoint": "[email protected]",
        "Protocol": "email",
        "PendingConfirmation": "false",
        "ConfirmationWasAuthenticated": "true",
        "SubscriptionArn": "arn:aws:sns:ap-northeast-1:xxxxxxxxxxxx:cm-hirai:xxxxxx"
    }
}

ConfirmationWasAuthenticated属性の値がtrueになれば、メール本文からは登録解除が行われません。

設定したSNSトピックからメールを送ってみます。

cm-hirai-screenshot 2024-07-16 15.24.50

メール受信されたことを確認します。また、メールに記載された登録解除のリンクをクリックしてみます。

cm-hirai-screenshot 2024-07-16 15.26.18
リンクをクリックしても、登録解除できないことが確認できます。
cm-hirai-screenshot 2024-07-16 15.27.02

これでSNSトピック設定完了です。

S3バケット作成

以下のS3バケットを2つ作成します。

  • 音声ファイル保存用(cm-hirai-audio-for-transcription)
  • 文字起こししたテキストファイルを保存用(cm-hirai-transcription-output)

バケット名以外の設定はすべてデフォルトのままとしています。

cm-hirai-screenshot 2024-07-12 21.22.44
cm-hirai-screenshot 2024-07-12 21.23.16

作成後、音声ファイル保存用(cm-hirai-audio-for-transcription)S3バケットのプロパティタブから、[このバケット内のすべてのイベントについて Amazon EventBridge に通知を送信する]を有効にします。

cm-hirai-screenshot 2024-07-16 15.56.10

有効にすると、変更が適用されるまで約 5 分かかります。

EventBridge に送信される Amazon S3 イベント通知メッセージの例は、以下の通りです。このメッセージは、ステートマシンの実行時の入力としても渡されます。

{
  "version": "0",
  "id": "17793124-05d4-b198-2fde-7ededc63b103",
  "detail-type": "Object Created",
  "source": "aws.s3",
  "account": "111122223333",
  "time": "2021-11-12T00:00:00Z",
  "region": "ca-central-1",
  "resources": [
    "arn:aws:s3:::DOC-EXAMPLE-BUCKET1"
  ],
  "detail": {
    "version": "0",
    "bucket": {
      "name": "DOC-EXAMPLE-BUCKET1"
    },
    "object": {
      "key": "example-key",
      "size": 5,
      "etag": "b1946ac92492d2347c6235b4d2611184",
      "version-id": "IYV3p45BT0ac8hjHg1houSdS1a.Mro8e",
      "sequencer": "617f08299329d189"
    },
    "request-id": "N4N7GDK58NMKJ12R",
    "requester": "123456789012",
    "source-ip-address": "1.2.3.4",
    "reason": "PutObject"
  }
}  

https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/enable-event-notifications-eventbridge.html

IAMポリシー作成

ステートマシン用のIAMポリシーを作成します。

以下の権限を持つポリシーを「cm-hirai-notify-transcription-policy」という名前で作成します。なお、アカウントIDは各自の環境に合わせて変更してください。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "s3:PutObject",
            "Resource": "arn:aws:s3:::cm-hirai-transcription-output/*"
        },
        {
            "Effect": "Allow",
            "Action": "s3:GetObject",
            "Resource": [
                "arn:aws:s3:::cm-hirai-transcription-output/*",
                "arn:aws:s3:::cm-hirai-audio-for-transcription/*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": "transcribe:GetTranscriptionJob",
            "Resource": "arn:aws:transcribe:ap-northeast-1:xxxxxxxxxxxx:transcription-job/*"
        },
        {
            "Effect": "Allow",
            "Action": "transcribe:StartTranscriptionJob",
            "Resource": "*"
        }
    ]
}

SNSのメール送信の権限は、ステートマシン作成時に自動生成されるIAMロールとポリシーに自動で追加されるため、このポリシーには含めません。

ステートマシン作成

Step Functions のステートマシンを作成します。

cm-hirai-screenshot 2024-07-12 21.48.15

まず、ステートマシンの画面からコードタブに移動し、以下のJSONコードを貼り付けます。

{
  "Comment": "Audio transcription and notification workflow",
  "StartAt": "StartTranscriptionJob",
  "States": {
    "StartTranscriptionJob": {
      "Type": "Task",
      "Resource": "arn:aws:states:::aws-sdk:transcribe:startTranscriptionJob",
      "Parameters": {
        "TranscriptionJobName.$": "$$.Execution.Name",
        "LanguageCode": "ja-JP",
        "Media": {
          "MediaFileUri.$": "States.Format('s3://{}/{}', $.detail.bucket.name, $.detail.object.key)"
        },
        "OutputBucketName": "cm-hirai-transcription-output",
        "OutputKey.$": "States.Format('{}.json', $$.Execution.Name)",
        "Settings": {
          "ShowSpeakerLabels": true,
          "MaxSpeakerLabels": 2
        }
      },
      "ResultPath": "$.TranscriptionJob",
      "Next": "Wait"
    },
    "Wait": {
      "Type": "Wait",
      "Seconds": 1,
      "Next": "GetTranscriptionJob"
    },
    "GetTranscriptionJob": {
      "Type": "Task",
      "Resource": "arn:aws:states:::aws-sdk:transcribe:getTranscriptionJob",
      "Parameters": {
        "TranscriptionJobName.$": "$.TranscriptionJob.TranscriptionJob.TranscriptionJobName"
      },
      "ResultPath": "$.GetTranscriptionJobResult",
      "Next": "CheckStatus"
    },
    "CheckStatus": {
      "Type": "Choice",
      "Choices": [
        {
          "Variable": "$.GetTranscriptionJobResult.TranscriptionJob.TranscriptionJobStatus",
          "StringEquals": "COMPLETED",
          "Next": "GetTranscriptionContent"
        },
        {
          "Variable": "$.GetTranscriptionJobResult.TranscriptionJob.TranscriptionJobStatus",
          "StringEquals": "FAILED",
          "Next": "TranscriptionJobFailed"
        }
      ],
      "Default": "Wait"
    },
    "GetTranscriptionContent": {
      "Type": "Task",
      "Resource": "arn:aws:states:::aws-sdk:s3:getObject",
      "Parameters": {
        "Bucket": "cm-hirai-transcription-output",
        "Key.$": "States.Format('{}.json', $.GetTranscriptionJobResult.TranscriptionJob.TranscriptionJobName)"
      },
      "ResultSelector": {
        "Content.$": "States.StringToJson($.Body)"
      },
      "ResultPath": "$.TranscriptionContent",
      "Next": "PrepareNotification"
    },
    "PrepareNotification": {
      "Type": "Pass",
      "Parameters": {
        "subject": "【自動通知】音声ファイルの文字起こし完了",
        "message.$": "States.Format('音声ファイルが保存されましたので、文字起こし内容をお知らせいたします。\n\n■ トランスクリプションジョブ詳細\n・TranscribeジョブとStep Functionsステートマシン実行名: {}\n・音声ファイル: s3://{}/{}\n・文字起こしテキストファイル: s3://cm-hirai-transcription-output/{}.json\n\n■ 文字起こし内容\n{}\n\n■ 注意事項\n1. 上記の文字起こし内容は自動生成されたものです。正確性を要する場合は、音声ファイルの内容をご確認ください。\n2. 音声ファイルと文字起こしテキストファイルは、それぞれ指定されたS3バケット内に保存されています。必要に応じてダウンロードしてご利用ください。\n\n本通知は自動生成されています。\nご不明な点やお問い合わせは、システム管理者までご連絡ください。', $.GetTranscriptionJobResult.TranscriptionJob.TranscriptionJobName, $.detail.bucket.name, $.detail.object.key, $.GetTranscriptionJobResult.TranscriptionJob.TranscriptionJobName, $.TranscriptionContent.Content.results.transcripts[0].transcript)"
      },
      "Next": "SendNotification"
    },
    "SendNotification": {
      "Type": "Task",
      "Resource": "arn:aws:states:::sns:publish",
      "Parameters": {
        "TopicArn": "arn:aws:sns:ap-northeast-1:xxxxxxxxxxxx:cm-hirai",
        "Subject.$": "$.subject",
        "Message.$": "$.message"
      },
      "Next": "TranscriptionJobSucceeded"
    },
    "TranscriptionJobSucceeded": {
      "Type": "Succeed"
    },
    "TranscriptionJobFailed": {
      "Type": "Fail",
      "Cause": "Transcription job failed",
      "Error": "TranscriptionJobFailedException"
    }
  }
}
  • 以下は、各自の環境に合わせて変更してください。
    • TopicArn:SNSトピックARN
    • OutputBucketName:文字起こししたテキストファイルを保存するS3バケット名
  • Transcribeジョブ名と文字起こしした内容をS3バケットに保存するテキストファイル名は、ステートマシン実行名と同一にしています。
  • Pass state(PrepareNotification)で、メール本文を作成していますので、必要に応じて修正ください。

作成されるステートマシンのワークフローは以下の図の通りです。

cm-hirai-screenshot 2024-07-16 15.45.27

設定タブに移動し、ステートマシン名を入力します。

cm-hirai-screenshot 2024-07-16 15.46.14

画面右上の「作成」ボタンをクリックします。
IAMロールは自動的に作成されますが、TranscribeやS3へのアクセス権限は自動では付与されないため、手動で追加する必要があります。

cm-hirai-screenshot 2024-07-16 15.45.53

ステートマシンの作成後、自動生成されたIAMロールを確認すると、SNSへのアクセス権限用のIAMポリシーは自動作成されていました。

cm-hirai-screenshot 2024-07-16 15.48.36

SnsPublishScopedAccessPolicy-747e6644-9a81-485d-bdc2-1b4fa6982958
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": "sns:Publish",
            "Resource": "arn:aws:sns:ap-northeast-1:xxxxxxxxxxxx:cm-hirai"
        }
    ]
}

ステートマシンに自動生成されたIAMロールに、先ほど作成したステートマシン用のIAMポリシー(cm-hirai-notify-transcription-policy)を追加で適用します。

cm-hirai-screenshot 2024-07-16 15.47.31

EventBridgeルール作成

音声ファイル保存用S3バケット(cm-hirai-audio-for-transcription)に、拡張子WAVの音声ファイルがアップロードされたことをトリガーとして、ステートマシンを起動するEventBridgeルールを作成します。

ルール名を記入します。

cm-hirai-screenshot 2024-07-16 16.05.00

イベントパターンは以下の通りです。.wavではない音声ファイルの拡張子の場合、適宜修正ください。

cm-hirai-screenshot 2024-07-16 16.06.54

{
  "source": ["aws.s3"],
  "detail-type": ["Object Created"],
  "detail": {
    "bucket": {
      "name": ["cm-hirai-audio-for-transcription"]
    },
    "object": {
      "key": [{
        "suffix": ".wav"
      }]
    }
  }
}

ターゲットは、先程作成したステートマシンを指定します。

cm-hirai-screenshot 2024-07-16 16.07.10

以上の設定でEventBridgeルールを作成します。これにより、指定したS3バケットに.wavファイルがアップロードされると、自動的にステートマシンが起動されます。

テスト

テストのため、S3バケットcm-hirai-audio-for-transcriptionに、拡張子wavの音声ファイルをアップロードします。

すると、メールで以下の内容が送信されました。

cm-hirai-screenshot 2024-07-17 11.48.20

件名
【自動通知】音声ファイルの文字起こし完了
本文
音声ファイルが保存されましたので、文字起こし内容をお知らせいたします。

■ トランスクリプションジョブ詳細
・TranscribeジョブとStep Functionsステートマシン実行名: ee9c2644-ab6b-4da0-80b7-203521bb751a
・音声ファイル: s3://cm-hirai-audio-for-transcription/test1.wav
・文字起こしテキストファイル: s3://cm-hirai-transcription-output/ee9c2644-ab6b-4da0-80b7-203521bb751a.json

■ 文字起こし内容
あこんにちは。もしもし?クラスメソッドテテストです

■ 注意事項
1. 上記の文字起こし内容は自動生成されたものです。正確性を要する場合は、音声ファイルの内容をご確認ください。
2. 音声ファイルと文字起こしテキストファイルは、それぞれ指定されたS3バケット内に保存されています。必要に応じてダウンロードしてご利用ください。

本通知は自動生成されています。
ご不明な点やお問い合わせは、システム管理者までご連絡ください。

--
If you wish to stop receiving notifications from this topic, please click or visit the link below to unsubscribe:
https://sns.ap-northeast-1.amazonaws.com/unsubscribe.html?SubscriptionArn=arn:aws:sns:ap-northeast-1:xxxxxxxxxxxx:cm-hirai:xxxxx&[email protected]

Please do not reply directly to this email. If you have any questions or comments regarding this email, please contact us at https://aws.amazon.com/support

メール本文のうちIf you wish to stop receiving~~~略は、デフォルトで送信されます。

最後

本記事では、AWS Step Functionsを利用して、S3バケットに音声ファイルが保存されるたびにAmazon Transcribeで文字起こしを行い、その内容をメールで送信するシステムの構築方法を解説しました。

この仕組みを応用すれば、Amazon Connectで録音した音声ファイルがS3バケットに保存されたことをトリガーに、自動で文字起こしを行い、その内容をメールで送信するといった運用が可能になります。

参考

https://docs.aws.amazon.com/ja_jp/transcribe/latest/APIReference/API_TranscriptionJob.html#transcribe-Type-TranscriptionJob-LanguageCode

https://docs.aws.amazon.com/ja_jp/transcribe/latest/APIReference/API_GetTranscriptionJob.html

https://docs.aws.amazon.com/ja_jp/step-functions/latest/dg/connect-sns.html

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.